package com.xuecheng.publish.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.api.content.model.dto.CourseTeacherDTO;
import com.xuecheng.api.content.model.dto.TeachplanDTO;
import com.xuecheng.common.constant.CoursePubTemplateKey;
import com.xuecheng.common.enums.content.CourseModeEnum;
import com.xuecheng.common.exception.ExceptionCast;
import com.xuecheng.common.util.JsonUtil;
import com.xuecheng.publish.common.constant.CoursePublishErrorCode;
import com.xuecheng.publish.common.util.QiniuUtils;
import com.xuecheng.publish.entity.CourseMarket;
import com.xuecheng.publish.entity.CoursePub;
import com.xuecheng.publish.entity.CoursePubMsg;
import com.xuecheng.publish.mapper.CoursePubMapper;
import com.xuecheng.publish.service.CoursePubService;
import freemarker.template.Configuration;
import freemarker.template.Template;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 课程发布 服务实现类
 * </p>
 *
 * @author itcast
 */
@Slf4j
@Service
public class CoursePubServiceImpl extends ServiceImpl<CoursePubMapper, CoursePub> implements CoursePubService {

    @Autowired
    private Configuration configuration;

    @Value("${file.qiniu.accessKey}")
    private String accessKey;

    @Value("${file.qiniu.secretKey}")
    private String secretKey;

    @Value("${file.qiniu.bucket}")
    private String bucket;

    // 生成静态页面的位置
    @Value("${course.publish.position}")
    private String position;

    /**
     * 课程发布的页面
     *
     * @param coursePubMsg
     */
    @Override
    @Transactional
    public void publishPage(CoursePubMsg coursePubMsg) {

        // TODO: is_pub为1时才会生成详情页

        // 判断消息幂等性
        LambdaQueryWrapper<CoursePub> pubQueryWrapper = new LambdaQueryWrapper<>();
        pubQueryWrapper.eq(CoursePub::getId, coursePubMsg.getPubId());
        pubQueryWrapper.eq(CoursePub::getIsPub, CoursePub.IS_PUB);
        int count = this.count(pubQueryWrapper);
        // 若课程已经发布，记录日志，不要抛出异常，抛出异常后 spring retry 会重试
        if (count > 0) {
            log.info("课程已经发布完毕了，无需操作，coursePubId => ", coursePubMsg.getPubId());
            return;
        }

        // 生成课程页面
        CoursePub coursePub = null;
        String htmlString = null;
        try {
            coursePub = this.getById(coursePubMsg.getPubId());
            Map<String, Object> dataMap = generateDataMap(coursePub);
            Template template = null;
            template = configuration.getTemplate("learing_article.ftl");
            htmlString = FreeMarkerTemplateUtils.processTemplateIntoString(template, dataMap);
        } catch (Exception e) {
            log.error("生成课程发布页面失败，coursePubId => {}", coursePub.getId());
            ExceptionCast.cast(CoursePublishErrorCode.E_120209);
        }

        // 修改课程发布的状态为已发布
        LambdaUpdateWrapper<CoursePub> pubUpdateWrapper = new LambdaUpdateWrapper<>();
        pubUpdateWrapper.set(CoursePub::getIsPub, CoursePub.IS_PUB);
        pubUpdateWrapper.set(CoursePub::getChangeDate, LocalDateTime.now());
        pubUpdateWrapper.eq(CoursePub::getId, coursePub.getId());
        boolean pubUpdateResult = this.update(pubUpdateWrapper);
        if (!pubUpdateResult) {
            log.error("课程发布时修改课程发布状态失败，coursePubId => ", coursePub.getId());
            // 抛出异常时，spring retry 会进行消息重试
            ExceptionCast.cast(CoursePublishErrorCode.E_120214);
        }

        // 将静态页面上传到七牛云
        try {
            String htmlKey = position + coursePubMsg.getPubId() + ".html";
            QiniuUtils.upload2Qiniu(accessKey, secretKey, bucket, htmlString, htmlKey);
            log.info("静态页面上传七牛云完毕，key => {}", htmlKey);
        } catch (Exception e) {
            log.error("课程发布页面上传七牛云失败，coursePubId => ", coursePub.getId());
            ExceptionCast.cast(CoursePublishErrorCode.E_120210);
        }

    }

    /**
     * 生成课程发布数据模型，用于FreeMarker生成页面数据
     *
     * @param coursePub 课程发布对象
     * @return
     */
    private Map<String, Object> generateDataMap(CoursePub coursePub) {
        // 数据模型对象
        HashMap<String, Object> dataMap = new HashMap<>();
        // 构建课程发布数据
        dataMap.put(CoursePubTemplateKey.COURSEPUB, coursePub);
        // 构建课程营销数据
        CourseMarket courseMarket = JsonUtil.jsonToObject(coursePub.getMarket(), CourseMarket.class);
        dataMap.put(CoursePubTemplateKey.COURSEMARKET, courseMarket);
        // 构建课程教师数据
        List<CourseTeacherDTO> courseTeachers = JsonUtil.jsonToList(coursePub.getTeachers(), CourseTeacherDTO.class);
        dataMap.put(CoursePubTemplateKey.TEACHERKEY, courseTeachers);
        // 构建课程计划数据
        List<TeachplanDTO> teachplanNode = JsonUtil.jsonToList(coursePub.getTeachers(), TeachplanDTO.class);
        dataMap.put(CoursePubTemplateKey.TEACHPLANNODE, TeachplanDTO.class);
        // 构建课程模式
        CourseModeEnum[] courseModes = CourseModeEnum.values();
        dataMap.put(CoursePubTemplateKey.COURSETEACHMODEENUMS, courseModes);
        return dataMap;
    }
}
